<template>
  <!-- <div> -->
    <div
      :class="['dpro-select', { 'dpro-select-disabled': disabled }, { 'dpro-select-open': _placementVisible }, { 'dpro-select-allow-clear': allowClear && _value !== undefined }]"
      @click="clickTrigger"
    >
      <div class="dpro-select-selection" ref="dropdownTrigger">
        <div class="dpro-select-selection_rendered">
          <div class="dpro-select-selection-selected-value" v-if="_value !== undefined">{{ currentLable }}</div>
          <div class="dpro-select-selection_placeholder" v-else>{{ placeholder }}</div>
        </div>
        <span class="dpro-select-arrow">
          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" class="icon"><path d="M458.752 656.128 322.304 451.52A64 64 0 0 1 375.68 352h272.768a64 64 0 0 1 53.312 99.52L565.312 656.128a64 64 0 0 1-106.496 0z"/></svg>
        </span>
        <span class="dpro-select-selection_clear" @click.stop="clearSelect">
          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" class="icon"><path d="M512 0a512 512 0 1 1 0 1024A512 512 0 0 1 512 0zm165.888 280.384-5.568 4.736L512 445.44 351.68 285.12l-5.568-4.736a44.8 44.8 0 0 0-57.792 68.096l160.32 160.256L288.32 669.12a44.8 44.8 0 0 0 57.792 68.096l5.568-4.736L512 572.096 672.32 732.48l5.568 4.736a44.8 44.8 0 0 0 57.792-68.096L575.296 508.736 735.68 348.48a44.8 44.8 0 0 0-57.792-68.096z"/></svg>
        </span>
      </div>
      <!-- 添加绝对定位div元素：解决getPopupContainer没有设置非静态定位属性时的定位问题 -->
      <div ref="placementWrapper" style="position:absolute;left:0;top:0;width:100%;">
        <div
          :class="['dpro-select-dropdown', dropdownClassName ? dropdownClassName : '']"
          :style="{ 'top': `${top}px`, 'left': `${left}px`, 'width': `${width}px` }"
          v-show="_placementVisible"
        >
          <slot name="dropdownRender">
            <div>
              <ul class="dpro-select-dropdown-menu">
                <li
                  :class="['dpro-select-dropdown-menu-item', { 'dpro-select-dropdown-menu-item-selected': _value === item.value }]"
                  v-for="item in options"
                  :key="item.value"
                  @click="clickItem(item)"
                >{{ item.label }}</li>
              </ul>
            </div>
          </slot>
        </div>
      </div>
    </div>
  <!-- </div> -->
</template>

<script>
export default {
  name: 'DproSelect',
  props: {
    /**
     * 指定当前选中的条目
     */
    value: {
      type: [String, Number, Array],
      default: undefined
    },
    /**
     * options 数据，如果设置则不需要手动构造 selectOption 节点
     * array<{value, label, [disabled, key, title]}>
     */
    options: {
      type: Array,
      default: () => []
    },
    /**
     * 下拉根元素的类名称
     */
    dropdownClassName: {
      type: String
    },
    /**
     * 是否禁用
     */
    disabled: {
      type: Boolean,
      default: false
    },
    /**
     * 菜单渲染父节点。默认渲染到 body 上，如果你遇到菜单滚动定位问题，试试修改为滚动的区域，并相对其定位。
     */
    getPopupContainer: {
      type: Function,
      default: () => document.body
    },
    /**
     * 选择框默认文字
     */
    placeholder: {
      type: String,
      default: '请选择'
    },
    /**
     * 支持清除
     */
     allowClear: {
      type: Boolean,
      default: false
    },
    /**
     * 是否展开下拉菜单
     */
     open: {
      type: Boolean,
      default: undefined
    }
  },
  data() {
    return {
      popEl: '',
      placementVisible: false,
      valueNoProp: undefined, // props无value时内部存储值
      top: 0,
      left: 0,
      width: 0,
      popOffsetTop: 4, // 弹出层纵向偏移量

    }
  },
  computed: {
    _placementVisible() {
      return this.$props.open !== undefined ? this.$props.open : this.placementVisible;
    },
    _value: {
      get: function() {
        return this.$props.value !== undefined ? this.$props.value : this.valueNoProp;
      },
      set: function(val) {
        // console.log('setValue', val, this._value);
        val !== this._value && this.$emit('change', val, this.options);
        if(this.$props.value === undefined) {
          this.valueNoProp = val;
        } else {
          this.$emit('input', val);
        }
      }
    },

    containerNode() {
      return this.getPopupContainer();
    },
    // 未设置options参数时，显示_value值
    currentLable() {
      let item = this.options.find(item => item.value === this._value);
      return item ? item.label : this._value;
    }
  },
  watch: {
    // 父组件控制隐藏时移除点击事件监听
    _placementVisible(val) {
      // console.log('watch-_placementVisible', val);
      val && this.bindBodyClickEvent();
      !val && this.removeBodyClickEvent();
    }
  },
  mounted() {
    window.addEventListener('resize', this.resizeHandler, true);
  },
  beforeDestroy() {
    console.log('beforeDestroy-select1')
    // window.removeEventListener('resize', this.resizeHandler, true);
    // this.removeBodyClickEvent();
    // this.removeNode();
  },
  destroyed() {
    console.log('destroyed-select1', this.resizeHandler)
    window.removeEventListener('resize', this.resizeHandler, true);
    this.removeBodyClickEvent();
  },
  methods: {
    // 更新top和left值
    setPosition() {
      let triggerEl = this.$refs.dropdownTrigger;
      if(!triggerEl || !this.popEl) return;
      let clientRect = triggerEl.getBoundingClientRect(),
        placementClientRect = this.popEl.getBoundingClientRect();
      // console.log('clientRect', JSON.stringify(clientRect), 'placementClientRect', JSON.stringify(placementClientRect));
      this.top = clientRect.top + clientRect.height - placementClientRect.top + this.popOffsetTop;
      this.left = clientRect.left - placementClientRect.left;
      this.width = clientRect.width;
      // console.log(`top:${this.top};left:${this.left}`)
      return true;
    },
    appendNode() {
      // console.log('appendNode', this.popEl, this.$refs.placementWrapper);
      if(this.popEl) return;
      let popEl = this.$refs.placementWrapper;
      this.popEl = popEl.parentNode.removeChild(popEl);
      this.containerNode.appendChild(popEl);
    },
    removeNode() {
      if(!this.popEl || !this.containerNode.contains(this.popEl)) return;
      this.containerNode.removeChild(this.popEl);
    },
    clickTrigger() {
      // console.log('clickTrigger', this._placementVisible);
      if(this.disabled) return;
      this.setVisible(!this._placementVisible);
      // await this.$nextTick();
    },
    clickItem(item) {
      if(item.disabled) return;
      this._value = item.value;
      setTimeout(() => {
        this.setVisible(false);
      }, 120);
    },
    clearSelect() {
      this._value = undefined;
      this._placementVisible && this.setVisible(false);
    },
    bindBodyClickEvent() {
      // console.log('bindBodyClickEvent')
      document.body.addEventListener('click', this.clickBodyHandler, false);
    },
    removeBodyClickEvent() {
      // console.log('removeBodyClickEvent')
      document.body.removeEventListener('click', this.clickBodyHandler, false);
    },
    clickBodyHandler(e) {
      if(!this._placementVisible) return;
      // e.stopPropagation();
      let composedPath = e.composedPath();
      console.log('select-document-click', e);
      // console.log('composedPath', composedPath);
      if (
        composedPath.includes(this.$refs.placementWrapper) ||
        composedPath.includes(this.$refs.dropdownTrigger)
      ) {
        // 点击overlay下的元素时不触发隐藏
        // console.log('点击弹出层或触发层');
        return;
      }
      this.hidePlacement(17);
    },
    hidePlacement(delay = 500) {
      setTimeout(() => {
        this.setVisible(false);
      }, delay);
    },
    setVisible(visible) {
      console.log('setVisible', visible);
      // 每次显示时获取最新位置
      if(visible) {
        this.appendNode();
        this.setPosition();
      }

      if(this.$props.open === undefined) {
        this.placementVisible = visible;
      }
      this.$emit('dropdownVisibleChange', visible);

    },
    // 页面resize时更新定位
    resizeHandler() {
      // console.log('select-resizeHandler', this._placementVisible);
      this._placementVisible && this.setPosition();
    }
  }
}
</script>

<style lang="less">
@import url(../../styles/variables.less);
.dpro-select {
  position: relative;
  color: @text-color;
  font-size: 14px;
  display: inline-block;
  outline: 0;
  list-style: none;
}
.dpro-select-disabled {
  .dpro-select-selection {
    opacity: 0.8;
    cursor: not-allowed;
    border-color: rgba(217, 217, 217, .1);
    &:focus,
    &:hover {
      border-color: rgba(217, 217, 217, .1);
      box-shadow: none;
    }
  }
}
.dpro-select-open {
  .dpro-select-arrow {
    .icon {
      transform: rotate(180deg);
    }
  }
}
.dpro-select-allow-clear {
  .dpro-select-selection {
    &:hover {
      .dpro-select-arrow {
        opacity: 0;
        display: none;
      }
      .dpro-select-selection_clear {
        opacity: 1;
        display: inline-block;
      }
    }
  }
}
.dpro-select-selection {
  position: relative;
  height: 32px;
  cursor: pointer;
  display: block;
  background-color: @select-dropdown-bg;
  border: 1px solid transparent;
  border-radius: 4px;
  outline: none;
  transition: all .3s cubic-bezier(.645,.045,.355,1);
  user-select: none;
  &:focus,
  &:hover {
    border-color: @primary-color;
    box-shadow: 0 0 0 2px rgba(78, 104, 240, 0.2);
  }
  // &:hover {
  //   .dpro-select-selection_clear {
  //     opacity: 1;
  //   }
  // }
}
.dpro-select-selection_rendered {
  position: relative;
  margin: 0 24px 0 11px;
  line-height: 30px;
}
.dpro-select-selection-selected-value,
.dpro-select-selection_placeholder {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.dpro-select-selection_placeholder {
  user-select: none;
  opacity: 0.5;
}
.dpro-select-arrow,
.dpro-select-selection_clear {
  display: inline-block;
  position: absolute;
  top: 50%;
  right: 11px;
  margin-top: -6px;
  color: @text-color-secondary;
  font-size: 12px;
  line-height: 1;
  transform-origin: 50% 50%;
  font-style: normal;
  text-align: center;
  vertical-align: -0.125em;
  user-select: none;
  .icon {
    display: block;
    transition: transform .3s;
  }
}
.dpro-select-selection_clear {
  background: @select-dropdown-bg;
  opacity: 0;
  display: none;
  z-index: 1;
  border-radius: 50%;
  cursor: pointer;
  transition: color 0.3s ease, opacity 0.15s ease;
  &:hover {
    color: @text-color;
  }
}
.icon {
  width: 1em;
  height: 1em;
  vertical-align: -0.15rem;
  fill: currentColor;
  overflow: hidden;
}
.dpro-select-dropdown {
  box-sizing: border-box;
  position: absolute;
  display: block;
  margin: 0;
  padding: 0;
  font-size: 14px;
  color: @text-color;
  z-index: 1050;
  background-color: @select-dropdown-bg;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
  border-radius: 4px;
}
.dpro-select-dropdown-menu {
  margin: 0;
  padding: 4px 0;
  overflow: auto;
  list-style: none;
  outline: none;
}
.dpro-select-dropdown-menu-item {
  user-select: none;
  position: relative;
  display: block;
  padding: 5px 12px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 14px;
  line-height: 22px;
  cursor: pointer;
  transition: background .3s ease;
  &:hover {
    background-color: @primary-color;
  }
}
.dpro-select-dropdown-menu-item-selected {
  background-color: @primary-color;
  color: @text-color;
}
</style>